﻿using JMI_Nucleo.Enumerador;
using OR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace JMI_Nucleo.Classe
{
    public class JMIUtil
    {
        [DllImport("DllInscE32.dll")]
        static extern bool ConsisteInscricaoEstadual(string Inscr, string UF);

        public DataSet ListaParaDataSet<T>(IList list)
        {
            DataSet dataSet = new DataSet();
            CreateDataSet(dataSet, typeof(T), false);
            FillDataSet(typeof(T), list, dataSet, -1);
            CreateRelations(dataSet, typeof(T), null);
            return dataSet;
        }

        public DataTable ListaParaDataTable<T>(List<T> list)
        {
            DataTable dt = new DataTable();
            foreach (PropertyInfo info in typeof(T).GetProperties())
            {
                Type tipo = info.PropertyType;
                if (tipo.IsGenericType && tipo.GetGenericTypeDefinition() == typeof(Nullable<>))
                    tipo = Nullable.GetUnderlyingType(tipo);
                dt.Columns.Add(new DataColumn(info.Name, tipo));
            }
            foreach (T t in list)
            {
                DataRow row = dt.NewRow();
                foreach (PropertyInfo info in typeof(T).GetProperties())
                {
                    object value = info.GetValue(t, null);
                    if (value != null)
                    {
                        row[info.Name] = value;
                    }
                    else
                    {
                        row[info.Name] = DBNull.Value;
                    }
                }
                dt.Rows.Add(row);
            }
            return dt;
        }

        private void CreateDataSet(DataSet dataSet, Type type, bool isChildTable)
        {
            DataTable dataTable = new DataTable(type.Name);
            //Create the ID columns for having relation in the tables
            dataTable.Columns.Add(new DataColumn("ID2", typeof(int)));
            if (isChildTable)
            {
                dataTable.Columns.Add(new DataColumn("ParentID2", typeof(int)));
            }
            // Create the structure for the data tables to be
            // added in the the data set
            foreach (PropertyInfo pInfo in type.GetProperties())
            {
                if (pInfo.PropertyType.IsGenericType &&
                (pInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
                || pInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
                {
                    // If associate lists are there make then another table
                    CreateDataSet(dataSet, pInfo.PropertyType.GetGenericArguments()[0], true);
                }
                else
                {
                    dataTable.Columns.Add(new DataColumn(pInfo.Name, pInfo.PropertyType));
                }
            }
            //Add the table to the dataset
            dataSet.Tables.Add(dataTable);
        }
        private void FillDataSet(Type type, IList list, DataSet dataSet, int parentID)
        {
            PropertyInfo[] propertyInfos = type.GetProperties();
            DataTable dataTable = dataSet.Tables[type.Name];
            int id = dataTable.Rows.Count + 1;

            foreach (object item in list)
            {
                DataRow row = dataTable.NewRow();

                // Set new id and related parent id
                row["ID"] = id;
                if (parentID != -1)
                    row["ParentID"] = parentID;

                // Load all the data from the properties of the type
                // and save them into the datatable
                foreach (PropertyInfo info in propertyInfos)
                {
                    if (info.PropertyType.IsGenericType &&
                        (info.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
                        || info.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
                    {
                        IList subList = (IList)info.GetValue(item, null);
                        if (subList != null && subList.Count > 0)
                        {
                            FillDataSet(subList[0].GetType(),
                            subList,
                            dataSet, id);
                        }
                    }
                    else
                    {
                        row[info.Name] = info.GetValue(item, null);
                    }
                }

                dataTable.Rows.Add(row);
                id++;
            }
        }
        private void CreateRelations(DataSet dataSet, Type type, DataTable parentTable)
        {
            DataTable dataTable = dataSet.Tables[type.Name];

            // If parent table exsits then create relation
            // with child table on field Parent ID
            if (parentTable != null)
            {
                dataSet.Relations.Add(
                new DataRelation(parentTable.TableName + "_ID_"
                + "PARENTID_" + dataTable.TableName,
                parentTable.Columns["ID"],
                dataTable.Columns["ParentID"]));
            }

            // Check for other lists under current object
            // go for another relation if exists
            foreach (PropertyInfo pInfo in type.GetProperties())
            {
                if (pInfo.PropertyType.IsGenericType &&
                    (pInfo.PropertyType.GetGenericTypeDefinition() == typeof(List<>)
                    || pInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
                {
                    // If associate lists are there make then another table
                    CreateRelations(dataSet, pInfo.PropertyType.GetGenericArguments()[0], dataTable);
                }
            }
        }
                
        public string RemoveAcento(string texto)
        {
            string com_acento = @"ÁÀÃÂÄàáãâäÈÉÊËèéêëÌÍÎÏìíîïÒÓÕÔÖòóõôöÙÚÛÜùúûüÇç€º�Ññ-'";
            string sem_aceonto = @"AAAAAaaaaaEEEEeeeeIIIIiiiiOOOOOoooooUUUUuuuuCcCCONn  ";
            for (int i = 0; i < com_acento.Length; i++)
                texto = texto.Replace(com_acento[i], sem_aceonto[i]);
            return texto.ToUpper();
        }
        public string PrimeiraMaiuscula(string strString)
        {
            string strResult = "";
            if (strString.Length > 0)
            {
                strResult += strString.Substring(0, 1).ToUpper();
                strResult += strString.Substring(1, strString.Length - 1).ToLower();
            }
            return strResult;
        }
        public string GetCaminhoAplicacao()
        {
            return AppDomain.CurrentDomain.BaseDirectory;
        }
        public string RemoveMascara(string s)
        {
            StringBuilder dado = new StringBuilder();
            string aux = String.Empty;
            if (!String.IsNullOrEmpty(s))
            {
                foreach (char c in s)
                {
                    if (Char.IsNumber(c))
                        dado.Append(c);
                }
                aux = dado.ToString();
            }
            return aux;
        }
        public string TrataInscEstadual(string sIE)
        {
            string aux = String.Empty;
            aux = sIE.ToUpper();
            if (!aux.Contains("ISENTO"))
               aux = RemoveMascara(sIE);
            return aux;        
        }
        public bool ContemLetra(string letras)
        {
            if (letras.Where(c => char.IsLetter(c)).Count() > 0)
                return true;
            else
                return false;
        }
        public bool ContemNumero(string texto)
        {
            if (texto.Where(c => char.IsNumber(c)).Count() > 0)
                return true;
            else
                return false;
        }
        public ConfigBD GetInfoConexao()
        {
            string msgAltera = "Arquivo App.config não encontrado no diretório do sistema/ou inválido.";
            ConfigBD config = new ConfigBD();
            try
            {
                config.Servidor = ConfigurationManager.AppSettings["Servidor"];
                config.Porta = int.Parse(ConfigurationManager.AppSettings["Porta"]);
                config.Usuario = ConfigurationManager.AppSettings["Usuario"];
                config.Senha = ConfigurationManager.AppSettings["Senha"];
                config.Base = ConfigurationManager.AppSettings["Base"];
                config.Provedor = ConfigurationManager.AppSettings["Provedor"];                    
            }
            catch (Exception ex)
            {
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = msgAltera + "\n" + ex.Message;
                _info.Metodo = "public ConfigBD GetInfoConexao()";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
            return config;
        }
        public string GetProvedorUtilizado()
        {
            string _provedor = String.Empty;
            _provedor = ConfigurationManager.AppSettings["Provedor"];
            return _provedor;
        }
        public string AjustaDataAlteracao(DateTime data)
        {
            string retorno = "Data Alteração: ";
            retorno += data == DateTime.MinValue ? "__/__/____" : data.ToShortDateString();
            return retorno;
        }
        #region Metodos para controle de Datas
        public DateTime GetInicioMes()
        {
            DateTime primeiroDia = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);

            return primeiroDia;
        }
        public DateTime GetFinalMes()
        {
            DateTime ultimoDia = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month));

            return ultimoDia;
        }
        public DateTime AjustaData(string sData)
        {
            string aux = String.Empty;
            DateTime retorno = DateTime.MinValue;

            if (String.IsNullOrEmpty(sData))
                retorno = DateTime.MinValue;
            else
            {
                if (sData.Length == 10)
                    retorno = Convert.ToDateTime(sData);
                else if (sData.Length < 10)
                {
                    aux = sData;
                    aux = aux.Insert(2, "/");
                    aux = aux.Insert(5, "/");
                    retorno = Convert.ToDateTime(aux);
                }
            }

            return retorno;
        }
        #endregion
        #region Classe static para controle de propertys
        public static class cCampo<T> where T : new()
        {
            static BindingFlags flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Static;
            static List<FieldInfo> lstCampo = new List<FieldInfo>();
            static short nroCampo = 0;

            public static string GetPropriedade(string valor)
            {
                int indice = 0;

                indice = valor.IndexOf("<");

                string s = valor.Substring(1);
                indice = valor.IndexOf(">");
                s = s.Substring(0, indice - 1);

                return s;
            }

            public static List<FieldInfo> PreencheListaCampo(T obj)
            {
                lstCampo.Clear();
                foreach (FieldInfo f in obj.GetType().GetFields(flag))
                {
                    lstCampo.Add(f);
                    nroCampo++;
                }
                foreach (FieldInfo f in obj.GetType().BaseType.GetFields(flag))
                {
                    lstCampo.Add(f);
                    nroCampo++;
                }
                return lstCampo;
            }

            public static Object PopulaProperty(DbDataReader rd, Modelo m)
            {
                string campoTb, campoProp;
                object valor;

                lstCampo.Clear();
                lstCampo = cCampo<Modelo>.PreencheListaCampo(m);
                while (rd.Read())
                {
                    for (short x = 0; x < rd.FieldCount; x++)
                    {
                        campoTb = rd.GetName(x).ToUpper();
                        foreach (FieldInfo campo in lstCampo)
                        {
                            campoProp = campo.Name.ToUpper();
                            // Limpar property
                            if (campoProp.IndexOf(">") > 0)
                                campoProp = GetPropriedade(campoProp);
                            if (campoTb.ToUpper() == campoProp)
                            {
                                valor = (rd as DbDataReader)[campoTb];
                                switch (campo.FieldType.Name)
                                {
                                    case "Int16": { campo.SetValue(m, Convert.ToInt16(valor)); break; }
                                    case "Int32": { campo.SetValue(m, Convert.ToInt32(valor)); break; }
                                    case "String": { campo.SetValue(m, valor.ToString()); break; }
                                    case "DateTime": { campo.SetValue(m, Convert.ToDateTime(valor)); break; }
                                }
                                break;
                            }
                        }
                    }
                }
                return m;
            }
        }
        #endregion
        #region Metodos para validação e Formatação
        public bool isValidaTelefone(string telefone)
        {
            bool retorno = Regex.IsMatch(telefone, (@"^[(]{1}\d{2}[)]{1}\d{4}[-]{1}\d{4}$"));
            if (retorno == false)
            {
                JMIMsg.MsgAlerta("Telefone inválido.");
            }
            return retorno;
        }
        public bool isValidaCep(string cep, ref string CepFormatado)
        {
            bool retorno;
            if (cep.Length == 8)
            {
                cep = cep.Substring(0, 5) + "-" + cep.Substring(5, 3);
                CepFormatado = cep;
            }
            retorno = Regex.IsMatch(cep, ("[0-9]{5}-[0-9]{3}"));
            if (retorno == false)
            {
                JMIMsg.MsgAlerta("Cep inválido.");
            }
            return retorno;
        }
        public bool isValidaUF(string Uf)
        {
            string[] ESTADOS = { "SP", "MG", "RJ", "RS", "SC", "PR", "ES", "DF", "MT", "MS", "GO", "TO", "BA", "SE",
                                 "AL", "PB", "PE", "MA", "RN", "CE", "PI", "PA", "AM", "AP", "FN", "AC", "RR", "RO" };
            bool retorno = false;
            if (!String.IsNullOrEmpty(Uf))
            {
                for (short i = 0; i < ESTADOS.Length; i++)
                {
                    if (Uf.ToUpper().Equals(ESTADOS[i]))
                    {
                        retorno = true;
                        break;
                    }
                }
            }
            return retorno;
        }
        public bool IsValidaEmail(string email)
        {
            Regex rg = new Regex(@"^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$");
            return rg.IsMatch(email);
        }
        public bool IsValidaPIS(string Pis)
        {
            string pis = Pis;
            int[] multiplicador = new int[10] { 3,2,9,8,7,6,5,4,3,2 };
		    int soma;
		    int resto;

            if (pis.Trim().Length != 11)
                                           return false;

		    pis = pis.Trim();
		    pis = pis.Replace("-", "").Replace(".", "").PadLeft(11, '0');
            

		    soma = 0;
		    for (int i = 0; i < 10; i++)
		        soma += int.Parse(pis[i].ToString()) * multiplicador[i];

		    resto = soma % 11;

		    if ( resto < 2 )
		        resto = 0;
		    else
		        resto = 11 - resto;

		    return pis.EndsWith(resto.ToString());
	    }
        public bool CpfValido(string cpf)
		{
			int[] multiplicador1 = new int[9] { 10, 9, 8, 7, 6, 5, 4, 3, 2 };
			int[] multiplicador2 = new int[10] { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 };
			string tempCpf;
			string digito;
			int soma;
			int resto;

			cpf = cpf.Trim();
			cpf = cpf.Replace(".", "").Replace("-", "");

			if (cpf.Length != 11)
				return false;

			tempCpf = cpf.Substring(0, 9);
			soma = 0;
			for(int i=0; i<9; i++)
				soma += int.Parse(tempCpf[i].ToString()) * multiplicador1[i];

			resto = soma % 11;
			if ( resto < 2 )
				resto = 0;
			else
				resto = 11 - resto;

			digito = resto.ToString();

			tempCpf = tempCpf + digito;

			soma = 0;
			for(int i=0; i<10; i++)
				soma += int.Parse(tempCpf[i].ToString()) * multiplicador2[i];

			resto = soma % 11;
			if (resto < 2)
				resto = 0;
			else
				resto = 11 - resto;

			digito = digito + resto.ToString();

			return cpf.EndsWith(digito);
		}
	    public bool CnpjValido(string cnpj)
        {
            // Se vazio
            if (cnpj.Length == 0)
                return false;
            //Expressao regular que valida cpf
            Regex rgx = new Regex(@"^\d{2}.?\d{3}.?\d{3}/?\d{4}-?\d{2}$");
            if (rgx.IsMatch(cnpj))
                return true;
            else
                return false;
            // Limpa caracteres especiais
            cnpj = cnpj.Trim();
            cnpj = cnpj.Replace(".", "").Replace("-", "").Replace("/", "").Replace(" ", "");
            cnpj = cnpj.Replace("+", "").Replace("*", "").Replace(",", "").Replace("?", "");
            cnpj = cnpj.Replace("!", "").Replace("@", "").Replace("#", "").Replace("$", "");
            cnpj = cnpj.Replace("%", "").Replace("¨", "").Replace("&", "").Replace("(", "");
            cnpj = cnpj.Replace("=", "").Replace("[", "").Replace("]", "").Replace(")", "");
            cnpj = cnpj.Replace("{", "").Replace("}", "").Replace(":", "").Replace(";", "");
            cnpj = cnpj.Replace("<", "").Replace(">", "").Replace("ç", "").Replace("Ç", "");
            // Se comtem letras
            if (this.ContemLetra(cnpj))
                return false;
            else
                return true;
            // Se o tamanho for < 11 entao retorna como inválido
            if (cnpj.Length != 14)
                return false;
            // Caso coloque todos os numeros iguais
            switch (cnpj)
            {       //00000000000000
                case "11111111111111":
                    return false;
                case "00000000000000":
                    return false;
                case "22222222222222":
                    return false;
                case "33333333333333":
                    return false;
                case "44444444444444":
                    return false;
                case "55555555555555":
                    return false;
                case "66666666666666":
                    return false;
                case "77777777777777":
                    return false;
                case "88888888888888":
                    return false;
                case "99999999999999":
                    return false;
            }
            int[] multiplicador1 = new int[12] { 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
            int[] multiplicador2 = new int[13] { 6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2 };
            int soma;
            int resto;
            string digito;
            string tempCnpj;
            cnpj = cnpj.Trim();
            cnpj = cnpj.Replace(
            ".", "").Replace("-", "").Replace("/", "");
            if (cnpj.Length != 14)
                return false;
            tempCnpj = cnpj.Substring(0, 12);
            soma = 0;
            for (int i = 0; i < 12; i++)
                soma += int.Parse(tempCnpj[i].ToString()) * multiplicador1[i];
            resto = (soma % 11);
            if (resto < 2)
                resto = 0;
            else
                resto = 11 - resto;
            digito = resto.ToString();
            tempCnpj = tempCnpj + digito;
            soma = 0;
            for (int i = 0; i < 13; i++)
                soma += int.Parse(tempCnpj[i].ToString()) * multiplicador2[i];
            resto = (soma % 11);
            if (resto < 2)
                resto = 0;
            else
                resto = 11 - resto;
            digito = digito + resto.ToString();
            return cnpj.EndsWith(digito);
        }
        public bool InscEstadualValida(string pInsc, string pUF)
        {
            // Se vazio
            if (pInsc.Length == 0)
                return false;
            // Limpa caracteres especiais
            pInsc = pInsc.Trim();
            pInsc = pInsc.Replace(".", "").Replace("-", "").Replace("/", "").Replace(" ", "");
            pInsc = pInsc.Replace("+", "").Replace("*", "").Replace(",", "").Replace("?", "");
            pInsc = pInsc.Replace("!", "").Replace("@", "").Replace("#", "").Replace("$", "");
            pInsc = pInsc.Replace("%", "").Replace("¨", "").Replace("&", "").Replace("(", "");
            pInsc = pInsc.Replace("=", "").Replace("[", "").Replace("]", "").Replace(")", "");
            pInsc = pInsc.Replace("{", "").Replace("}", "").Replace(":", "").Replace(";", "");
            pInsc = pInsc.Replace("<", "").Replace(">", "").Replace("ç", "").Replace("Ç", "");
            //Caso a Inscricão e o Estado Estejam Certos, Retorna Verdadeiro
            if (ConsisteInscricaoEstadual(pInsc.Replace(".", "").Replace("-", ""), pUF))
                return false;  // notei que aqui em varios exemplos na internet estava invertido o verdadeiro/falso
            else
                return true;
        }
        #endregion
        #region Metodos para Conversão de imagens
        public void CopiaImagemPastaLocal(string Tabela, int Chave, string ArqImagem, ref string NovoCaminho)
        {
            string destino = String.Empty;
            NovoCaminho = String.Empty;
            // Criar pasta local para imagem
            string dir = GetCaminhoAplicacao();
            try
            {
                dir += "Imagem";
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

                destino = Path.Combine(dir, Tabela + Chave.ToString() + ".jpeg");
                File.Copy(ArqImagem, destino);
                NovoCaminho = destino;
            }
            catch (Exception exc)
            {
                throw new Exception("Erro ao copiar arquivo, " + exc.Message);
            }
        }
        public byte[] ConvertImageToByteArray(Image image, ImageFormat imageFormat)
        {
            if (image == null)
                return null;

            MemoryStream ms = new MemoryStream();
            image.Save(ms, imageFormat);
            return ms.ToArray();
        }
        public Image ConvertByteArrayToImage(byte[] byteArray)
        {
            if (byteArray == null || byteArray.Length == 0)
            {
                return (null);
            }

            return (Image.FromStream(new MemoryStream(byteArray)));
        }
        public void GravaImagemDisco(Image image, string Tabela, int Chave)
        {
            try
            {
                string dir = GetCaminhoAplicacao();
                dir += "Imagem";
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);

                if (!Directory.Exists(Path.Combine(dir, Tabela)))
                    Directory.CreateDirectory(Path.Combine(dir, Tabela));
                string aux = Tabela + Chave.ToString() + ".jpeg";
                string arquivo = Path.Combine(dir, Tabela);
                arquivo += Path.Combine(arquivo, aux);
                image.Save(arquivo, ImageFormat.Jpeg);
            }
            catch (Exception ex)
            {
                #region Grava log local
                mLog _info = new mLog();
                _info._TipoErro = TipoErro.Erro;
                _info.Mensagem = "Erro na gravação imagem em disco. " + ex.Message;
                _info.Metodo = "public void GravaImagemDisco(Image image, string Tabela, int Chave)";
                _info.StackTrace = ex.StackTrace;
                _info.Tabela = String.Empty;
                LogLocal.Info = _info;
                LogLocal.Gravar();
                #endregion
            }
        }
        public string RetornaImagemDisco(string Tabela, int Chave)
        {
            string caminho = String.Empty;

            string dir = GetCaminhoAplicacao();
            dir += "Imagem";
            if (Directory.Exists(dir))
            {
                if (Directory.Exists(Path.Combine(dir, Tabela)))
                {
                    string aux = Tabela + Chave.ToString() + ".jpg";
                    string arquivo = Path.Combine(dir, Tabela);
                    caminho += Path.Combine(arquivo, aux);
                }
            }
            return caminho;
        }
        #endregion
    }
}
